﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RaytracerLib.MathLib;
using System.Drawing;
using YAXLib;
using TomanuExtensions;

namespace RaytracerLib.Samplers
{
    public class HammersleySampler : LowDiscrepancySequenceSampler
    {
        protected int m_n = 1;
        private List<Vector2>[,] m_samples;
        protected int m_count;

        [YAXNode]
        public int BaseY = 3;

        protected override Vector2 NextSample()
        {
            int n = m_n;
            m_n++;

            return new Vector2(
                (n - 0.5) / m_count,
                LowDiscrepancyMath.RadicalInverse(n, BaseY));
        }

        public override IEnumerable<Vector2> GetSamples(Rectangle a_rect)
        {
            foreach (var p in a_rect.EnumPixels())
            {
                if (m_samples[p.X, p.Y] == null)
                    continue;

                foreach (var s in m_samples[p.X, p.Y])
                    yield return s;
            }
        }

        public override SamplerType SamplerType
        {
            get 
            {
                return SamplerType.Hammersley;
            }
        }

        internal override void RenderStart(RenderStartPhase a_phase)
        {
            base.RenderStart(a_phase);

            if (a_phase == RenderStartPhase.PrepareObjectToRender)
                PrepareSamples();
        }

        private void PrepareSamples()
        {
            m_samples = new List<Vector2>[Film.Width, Film.Height];
            m_count = Film.Width * Film.Height * Subresolution * Subresolution;

            for (int i=0; i<m_count; i++)
            {
                Vector2 sample = NextSample();

                Vector2 s = new Vector2(
                    sample.X * Film.Width, 
                    sample.Y * Film.Height);
                Point p = new Point((int)s.X, (int)s.Y);

                if (m_samples[p.X, p.Y] == null)
                    m_samples[p.X, p.Y] = new List<Vector2>();
                m_samples[p.X, p.Y].Add(s);
            }
        }
    }
}
